<script setup lang="ts">
import MenuBar from '@/views/components/menuBar/index.vue';
import { getUrlParams } from '@/utils/ruoyi'
import * as cornerstoneCore from '@cornerstonejs/core';
import * as cornerstoneTools from '@roos/cornerstone3d-tools';
const { RenderingEngine, Enums: coreEnums, cache, imageLoader, metaData } = cornerstoneCore
const { ViewportType, Events: coreEvents } = coreEnums;
const { Enums: toolEnums, ToolGroupManager, utilities: csToolsUtilities } = cornerstoneTools
const { Events: toolEvents } = toolEnums
import initCNR from './assets/initCNR'
import { bindDefaultTool } from './assets/toolFactory'
import ToolPad from './components/tool-pad/index.vue'
import ImageSelector from './components/image-selector/index.vue'
import {
    RenderingEngineId,
    AssistRenderingEngineId,
    ToolGroupId
} from './assets/constant'
import { setReferenceLinesViewportId } from './assets/toolFactory'
import { vec3 } from 'gl-matrix';
import * as cornerstoneDicomImageLoader from "@cornerstonejs/dicom-image-loader";
import { getInformationOfImage } from './assets/informationUtil'
const { wadouri } = cornerstoneDicomImageLoader;
import Information from './components/information/index.vue'
import View3d from './components/view3d/index.vue'
import HotKeyPad from './components/hotKeyPad/index.vue'
import ExportSeries from "./components/export-series/index.vue"
import { deleteStorageSamilar } from '@/utils/ruoyi'


interface FrameConfig {
    viewportId: string,
    seriesIndex: number,
    imageIndex: number,
    imageCount: number,
    wl: number,
    ww: number,
    zoom: number,
    rotation: number,
    metaData?: any
}

/*========================================>( 作用域属性 )<========================================*/
//异步IPC
const _ipcs = {
    init: (p: string) => {
        //这里选择的是异步多次传输文件，防止一次图像传输过多，导致内存崩溃
        window.$.send('DCMVIEW-OPEN-FILE', { p })
    },
    jumpTolist(){
        window.$.send('JUMP-LIST-PAGE')
    }
}

//本页面图像渲染器
let _RenderingEngine: any = undefined

//本页面辅助图像渲染器
let _AssistRenderingEngine: any = undefined

//frame上切换series的option值
const _seriesIndexOptions: any = []

//用户研究信息
let _studyInfo: { device?: string, age?: string, gender?: string, name?: string, locate?: string } = {}

//当前dom滚动时，联合滚动的domindex，用于减少平行计算，重新渲染dom的时候清除
let _cacheUnionScrollData: Array<any> = []

//cvsBox的变化值
let _cvsWH: string | undefined = undefined

//当前辅助定位图的可选series
let _crossSeriesIndexs: Array<number> = []

//单次导入的文件imageId列表
let _uploadImageIds: Array<string> = []

//监听是否单次的判断定时任务
let _importImageTask: any = undefined

//双击切换窗格时的缓存
let _layoutCache: any = undefined

//接收数据
let _receivedList: Array<any> = []

/*========================================>( 模板属性 )<========================================*/
//菜单栏配置
const menuBarTitle = ref<string>()

const menuBarMenus = ref<Array<any>>([
    {
        name:'返回列表',
        icon:'jump',
        mark:'tolist'
    }
])

//储存最原始的请求数据
const originData = ref<Array<{ seriesId: string, imageIds: Array<string>, seriesIndex: number, studyId?: string }>>([])

//储存每个frame的配置属性，TODO属性暂定
const frameConfigs = ref<Array<FrameConfig | undefined>>([])

//保存series顺序，用于拖拽排序
const seriesPriority = ref<Array<number | string>>([])

//TODO 因为性能很好，暂时不知道loading的设计，晚点test的时候再说
const loading = ref<boolean>(false)

//目前活跃的frame
const activeFrameIndex = ref<number>(0)

//本页面唯一工具组
const toolGroup = ref<any>()

//图像series窗格布局
// const layoutConfig = ref<Array<number>>([2, 2])
const layoutConfig = ref<Array<number>>([1])

//是否平行图像联合滚动，后期如果_couldReference为true，展示一个checkbox切换值
const enableUnionScroll = ref<boolean>(true);

//封面信息
const seriesCovers = ref<Array<any>>([])

//目前活跃的seriesCover
const activeSeriesIndex = ref<number>(0)

//是否显示辅助定位图的控制器
const showAssistControl = ref<boolean>(false)

//辅助图显示的序列index
const assistSeriesIndex = ref<number>(0)

//需要加载的图像数量
const needLoadImageCount = ref<number>(0)

//已经加载的图像数量
const alreadyLoadImageCount = ref<number>(0)

//正在自动播放中的frameIdx
const playStatus = ref<any>({})

//是否显示图像信息框
const showInformation = ref<boolean>(false)

//当年图象的Information
const activeImageInformation = ref<any>()

//暂存frame鼠标移动事件
const frameMouseMoveEvent = ref<any>()

//是否显示图像选择器
const showImageSelector = ref<boolean>(true)

//是否显示3d框体
const showView3d = ref<boolean>(false)

//当前渲染第几个序列的3d图像
const active3dIndex = ref<number>(0)

//是否显示快捷键说明
const showHotKeyPad = ref<boolean>(false)

//导出的数据
const exportSeriesData = ref();

//是否显示导出
const exportSeriesVisible = ref<boolean>(false)

//是否拥有定位线：目前DX外都有
let couldReference = ref<boolean>(false)




/*========================================>( dom属性 )<========================================*/
//本页面所有dom
const domCvs = ref()
//辅助定位图dom
const domAssist = ref()
//图像box的dom
const domCvsBox = ref()
//工具组件的dom
const domToolPad = ref()
//序列选择器的dom
const domImageSelector = ref()
//辅助定位图的dom
const domAssistBox = ref()
//上传器，隐藏不显示
const uploader = ref()


/*========================================>( 计算属性 )<========================================*/
//根据dom数量变化和series顺序变化计算ViewportInputArray
const calcViewportInputArray = computed(() => {
    const viewportInputArray = []
    const elements = Array.isArray(domCvs.value) ? domCvs.value : [domCvs.value]
    //不知为何refdom在flex布局下动态展现后，顺序会发生变化，这里需要排序
    elements.sort((a: any, b: any) => a.dataset.index - b.dataset.index)
    for (const [domIndex, dom] of elements.entries()) {
        const seriesId = seriesPriority.value[domIndex]
        if (seriesId === undefined) {
            viewportInputArray.push(undefined)
            continue
        }
        const data = originData.value.find(i => i.seriesId === seriesId)
        viewportInputArray.push({
            seriesId,
            viewportId: `viewport:${domIndex}:${seriesId}`,
            type: ViewportType.STACK,
            element: dom,
            imageIds: data?.imageIds,
        })
    }
    return viewportInputArray
})

//计算加载进度
const calcLoading = computed(() => {
    const process = needLoadImageCount.value ? Math.ceil(alreadyLoadImageCount.value / needLoadImageCount.value * 100) : 0
    return process
})

const emits = defineEmits(['msg'])


/*========================================>( dom监听方法 )<========================================*/
//监听鼠标在assistDom上
const domMouseOverAssist = (e: any, isOver?: boolean) => {
    showAssistControl.value = isOver ?? false
}

//监听鼠标在dom上按下
const domMouseDownListener = (e: any) => {
    const { dataset } = e.srcElement
    const { index } = dataset
    setFrameActive(index)
}

//监听鼠标在dom上滚动
const domMouseScrollListener = (e: any) => {
    const { direction } = e.detail.wheel
    const { dataset } = e.srcElement
    const { index } = dataset
    setFrameActive(index)
    //联合滚动
    if (couldReference.value && enableUnionScroll.value) {
        const { viewportId: sourseViewportId } = calcViewportInputArray.value[index] ?? {}
        if (!_cacheUnionScrollData[index]) {
            _cacheUnionScrollData[index] = []
            //没有缓存，开始计算
            //循环所有dom的图像，判断与自己是否是平行的，如果是，则允许联合滚动
            for (const [targetIndex, viewportInputArray] of calcViewportInputArray.value.entries()) {
                if (targetIndex == index) {
                    //轮循到自己，跳过
                    continue
                }
                const { viewportId: targetViewportId } = viewportInputArray ?? {}
                if (!targetViewportId) continue
                const { viewPlaneNormal: soursePlaneNormal } = _RenderingEngine.getViewport(sourseViewportId).getCamera()
                const { viewPlaneNormal: targetPlaneNormal } = _RenderingEngine.getViewport(targetViewportId).getCamera()
                if (isParallel(soursePlaneNormal, targetPlaneNormal)) {
                    _cacheUnionScrollData[index].push(targetIndex)
                }
            }
        }
        //开始联合滚动
        _cacheUnionScrollData[index].forEach((targetIndex: number) => {
            const { viewportId } = calcViewportInputArray.value[targetIndex] ?? {}
            const viewport = _RenderingEngine.getViewport(viewportId)
            viewport.scroll(direction)
        });
    }
}

//监听鼠标在frame上移动
const domMouseMoveListener = (e: any) => {
    frameMouseMoveEvent.value = e
}

//监听dom渲染图像结束
const imageRenderedListener = (e: any) => {
    const { dataset } = e.srcElement
    const { index } = dataset
    renderStudyInfoOfFrameIndex(index)
}

//监听鼠标双击
const domDoubleClickListener = (e: any) => {
    //如果是多窗格，则双击切换单窗格并展示此双击序列
    //如果是单窗格，存在窗格cache则还原成目标数量窗格
    const { dataset } = e.srcElement
    const { index } = dataset
    console.log(dataset, index)
    if (frameConfigs.value.length > 1) {
        //多窗格
        const frameConf = frameConfigs.value[index]
        const seriesIndex = frameConf?.seriesIndex ?? 0
        const { seriesId } = originData.value[seriesIndex]
        _layoutCache = {
            layout: layoutConfig.value,
            activeIndex: index,
            seriesP: seriesPriority.value,
        }
        layoutConfig.value = [1]
        seriesPriority.value = [seriesId]
        nextTick(async () => {
            await renderImage()
            setFrameActive(0)
        })
    } else {
        //单窗格
        if (_layoutCache) {
            const { layout, activeIndex, seriesP } = _layoutCache
            layoutConfig.value = layout
            seriesPriority.value = seriesP
            nextTick(async () => {
                await renderImage()
                setFrameActive(activeIndex)
                _layoutCache = undefined
            })
        }
    }
}

/*========================================>( 普通方法 )<========================================*/
//计算frame的index
const ftd = (ldx: number, rdx: number, line: number) => {
    return ldx * line + rdx - 1
}

//计算图像之间是否平行
const EPSILON = 1e-3
const isParallel = (vec1: any, vec2: any) => {
    return Math.abs(vec3.dot(vec1, vec2)) > 1 - EPSILON;
}

//计算储存相交图像
const checkCross = async (sourceFrameIndex: number) => {
    if (originData.value.length <= 1) return []
    const { viewportId: sourceViewportId, seriesId: sourceSeriesId } = calcViewportInputArray.value[sourceFrameIndex] ?? {}
    const { viewPlaneNormal: sourcePlaneNormal } = _RenderingEngine.getViewport(sourceViewportId).getCamera()
    _crossSeriesIndexs = []
    for (const { seriesId, imageIds, seriesIndex } of originData.value) {
        if (sourceSeriesId === seriesId) continue //如果是自己，跳过
        const loadImageId = imageIds[0]
        await imageLoader.loadImage(loadImageId)
        let imagePlaneModule = metaData.get('imagePlaneModule', loadImageId)
        if (!imagePlaneModule) {
            return
        }
        imagePlaneModule = metaData.get('imagePlaneModule', loadImageId)
        let { rowCosines, columnCosines } = imagePlaneModule;
        rowCosines ||= [1, 0, 0];
        columnCosines ||= [0, 1, 0];
        const viewPlaneNormal = vec3.cross([0, 0, 0], columnCosines, rowCosines)
        if (!isParallel(sourcePlaneNormal, viewPlaneNormal)) {
            //找到不平行图像
            _crossSeriesIndexs.push(seriesIndex)
        }
    }
}


//读取未加载图像的viewPlaneNormal用于判断图像是否平行
const initAssistImage = async (crossIndex: number) => {
    if (!_crossSeriesIndexs.length) return
    const targetSeriesIndex = _crossSeriesIndexs[crossIndex]
    if (targetSeriesIndex === undefined) return
    const d = originData.value.find(e => targetSeriesIndex === e.seriesIndex)
    if (!d) return
    const { imageIds, seriesId } = d
    assistSeriesIndex.value = targetSeriesIndex
    const viewportId = `assist:${seriesId}`
    const elements = Array.isArray(domAssist.value) ? domAssist.value : [domAssist.value]
    const viewportInput = {
        viewportId,
        type: ViewportType.STACK,
        element: elements[0]
    }
    let renderingEngineId = AssistRenderingEngineId
    _AssistRenderingEngine = new RenderingEngine(renderingEngineId)
    _AssistRenderingEngine.enableElement(viewportInput);
    const viewport = _AssistRenderingEngine.getViewport(viewportId)
    await viewport.setStack([imageIds[0]])
    viewport.render()
    toolGroup.value.addViewport(viewportId, renderingEngineId);
}


//渲染标注层
const renderStudyInfoOfFrameIndex = (index: number) => {
    const elements = Array.isArray(domCvs.value) ? domCvs.value : [domCvs.value]
    //不知为何refdom在flex布局下动态展现后，顺序会发生变化，这里需要排序
    elements.sort((a: any, b: any) => a.dataset.index - b.dataset.index)
    const element = elements[index]
    if (!element) return
    //1.展示图像标签
    //获取数据
    if (!frameConfigs.value[index]) return
    const { viewportId, seriesIndex, imageCount } = frameConfigs.value[index]
    const { seriesId } = originData.value[seriesIndex ?? 0]
    if (typeof seriesId === 'string' && seriesId.indexOf('import') > -1) {
        return
    }
    const viewport = _RenderingEngine.getViewport(viewportId)
    const imageIndex = viewport.getCurrentImageIdIndex() + 1
    frameConfigs.value[index].imageIndex = imageIndex
    const { voiRange } = viewport.getProperties()
    const { upper, lower } = voiRange
    const top_left = [
        _studyInfo.name + ' - ' + _studyInfo.gender + ' - ' + _studyInfo.age,
        `${_studyInfo.device} : ${imageIndex}/${imageCount}`
    ]
    // const top_right = [//差一个 imageId比

    //     // `F: ${viewport.getCurrentImageIdIndex() + 1}/${imageCount}`
    // ]
    const bottom_left = [
        `W/L: ${upper - lower}/${(upper + lower) / 2}`,
        'Z: ' + viewport.getZoom().toFixed(2),
    ]
    const bottom_right = [
        _studyInfo.locate,
        originData.value[index].studyId ? 'SID: ' + originData.value[index].studyId : '',
    ]
    //开始渲染
    const canvas = element.getElementsByTagName('canvas')[0]
    const cvsWidth = canvas.width
    const cvsHeight = canvas.height
    const cvs = canvas.getContext('2d')
    cvs.fillStyle = '#FFFFCC'
    cvs.font = '12px Arial';
    //top_left
    for (const [index, v] of top_left.entries()) {
        cvs.fillText(v, 10, 16 * (index + 1))
    }
    //top_right
    // for (const [index, v] of top_right.entries()) {
    //     cvs.fillText(v, cvsWidth - 100, 16 * (index + 1))
    // }
    //bottom_left
    for (const [index, v] of bottom_left.entries()) {
        cvs.fillText(v, 10, cvsHeight - 10 - 16 * (index))
    }
    //bottom_right
    for (const [index, v] of bottom_right.entries()) {
        cvs.fillText(v, cvsWidth - 60, cvsHeight - 10 - 16 * (index))
    }
}


//活跃frame的方法
const setFrameActive = (index?: number) => {
    const aimIndex = index ?? activeFrameIndex.value
    activeFrameIndex.value = aimIndex
    const { viewportId } = calcViewportInputArray.value[aimIndex] ?? {}
    if (viewportId) {
        setReferenceLinesViewportId(toolGroup.value, viewportId)
    }
    // for (const v of calcViewportInputArray.value) {
    //     if (v) {
    //         setScaleOverlayViewportId(toolGroup.value, v.viewportId)
    //     }
    // }
}


//根据默认窗格初始化seriesPriority
const initSeriesPriority = () => {
    const elements = Array.isArray(domCvs.value) ? domCvs.value : [domCvs.value]
    seriesPriority.value = []
    for (const [index] of elements.entries()) {
        if (index >= originData.value.length) return
        const { seriesId } = originData.value[index]
        seriesPriority.value.push(seriesId)
    }
}

//清除缓存，渲染所有dom的图像
const renderImage = async () => {
    _cacheUnionScrollData = []
    let renderingEngineId = RenderingEngineId
    let toolGroupId = ToolGroupId
    if (_RenderingEngine) {
        ToolGroupManager.destroyToolGroup(toolGroupId)
        _RenderingEngine.destroy()
        renderingEngineId = RenderingEngineId
    }
    if (_AssistRenderingEngine) {
        _AssistRenderingEngine.destroy()
    }
    _RenderingEngine = new RenderingEngine(renderingEngineId);
    toolGroup.value = ToolGroupManager.createToolGroup(toolGroupId);
    frameConfigs.value = []
    for (const [index, vi] of calcViewportInputArray.value.entries()) {
        console.log('calcViewportInputArray', vi)
        if (!vi) {
            frameConfigs.value.push(undefined)
            continue
        }
        const { viewportId, imageIds, element, seriesId } = vi
        _RenderingEngine.enableElement(vi)
        const viewport = _RenderingEngine.getViewport(viewportId);
        await viewport.setStack(imageIds);
        viewport.render();
        toolGroup.value.addViewport(viewportId, renderingEngineId);
        if (!imageIds || !imageIds.length) return
        const seriesIndex = originData.value.find(e => e.seriesId === seriesId)?.seriesIndex
        frameConfigs.value.push(createframeConfig(viewportId, seriesIndex ?? 0,))
        element.removeEventListener(toolEvents.MOUSE_DOWN, domMouseDownListener)
        element.addEventListener(toolEvents.MOUSE_DOWN, domMouseDownListener)
        element.removeEventListener(toolEvents.MOUSE_WHEEL, domMouseScrollListener)
        element.addEventListener(toolEvents.MOUSE_WHEEL, domMouseScrollListener)
        element.removeEventListener(toolEvents.MOUSE_MOVE, domMouseMoveListener)
        element.addEventListener(toolEvents.MOUSE_MOVE, domMouseMoveListener)
        element.removeEventListener(coreEvents.IMAGE_RENDERED, imageRenderedListener)
        element.addEventListener(coreEvents.IMAGE_RENDERED, imageRenderedListener)
        element.removeEventListener(toolEvents.MOUSE_DOUBLE_CLICK, domDoubleClickListener)
        element.addEventListener(toolEvents.MOUSE_DOUBLE_CLICK, domDoubleClickListener)

    }
    // _RenderingEngine.render()

    //如果是单窗格，初始化辅助定位dom
    if (seriesPriority.value.length === 1 && originData.value.length > 1 && couldReference.value) {
        await checkCross(0)
        await initAssistImage(0)
        const listenerDom = Array.isArray(domAssistBox.value) ? domAssistBox.value[0] : domAssistBox.value
        listenerDom.removeEventListener('mouseover', (e: any) => { domMouseOverAssist(e, true) })
        listenerDom.addEventListener('mouseover', (e: any) => { domMouseOverAssist(e, true) })
        listenerDom.removeEventListener('mouseleave', domMouseOverAssist)
        listenerDom.addEventListener('mouseleave', domMouseOverAssist)

    }
    bindDefaultTool(toolGroup.value)
    domToolPad.value.enableLastTool()
}

//创建目标frame的配置bean
const createframeConfig = (viewportId: string, seriesIndex: number) => {
    const viewport = _RenderingEngine.getViewport(viewportId)
    const { voiRange } = viewport.getProperties()
    const { upper, lower } = voiRange
    const imageIds = viewport.getImageIds()
    return {
        viewportId,
        imageCount: imageIds.length,
        seriesIndex,
        imageIndex: viewport.getCurrentImageIdIndex(),
        rotation: viewport.getRotation(),
        zoom: viewport.getZoom(),
        ww: upper - lower,
        wl: (upper + lower) / 2
    }
}

/*========================================>( 监听方法 )<========================================*/
//监听dicom的上传,单词上传的一个或多个文件视为一个序列
const handleUploadDicom = (file: any) => {
    loading.value = true
    const uploadImageId = wadouri.fileManager.add(file);
    _uploadImageIds.push(uploadImageId)
    if (_importImageTask) {
        clearTimeout(_importImageTask)
        _importImageTask = undefined
    }
    _importImageTask = setTimeout(async () => {
        //执行渲染新增序列，_uploadImageIds作为一个新series添加到series
        const image = await imageLoader.loadImage(uploadImageId);
        // const imageSrc = dcmToImg(image)
        console.log('imageSrc', image)
        const seriesIndex = originData.value.length
        const seriesId = 'import:' + new Date().getTime()
        originData.value.push({
            seriesId,
            imageIds: _uploadImageIds,
            seriesIndex,
        })
        seriesCovers.value.push({
            id: seriesId,
            length: _uploadImageIds.length
        })
        _seriesIndexOptions.push({ value: seriesIndex, label: `导入:${(seriesIndex + 1)}` })
        initSeriesPriority()
        await renderImage()
        setFrameActive(0)
        _uploadImageIds = []
        loading.value = false
    }, 2000);
    return false
}

//监听frame上series变化
const handleFrameSeriesIndexChanged = (seriesIndex: number, targetIndex: number) => {
    handleSeriesDrag(originData.value[seriesIndex].seriesId, targetIndex)
}


//监听series拖拽事件
const handleSeriesDrag = async (seriesId: string, targetIndex: number) => {
    if (targetIndex < seriesPriority.value.length) {
        //1.如果index上有值，直接替换，
        console.log('移动', seriesId, targetIndex)
        seriesPriority.value[targetIndex] = seriesId
    } else {
        //2.如果超出index，则中间填充undefined
        const seriesPriorityAfter = []
        for (let i = 0; i <= targetIndex; i++) {
            if (i == targetIndex) {
                seriesPriorityAfter.push(seriesId)
            } else {
                seriesPriorityAfter.push(seriesPriority.value[i])
            }
        }
        seriesPriority.value = seriesPriorityAfter
    }
    await renderImage()
    await setFrameActive()
}

//监听切换series
const handleSeriesChanged = async (e: any) => {
    //使frame活跃：
    //1.如果是一个窗格，则重新渲染此窗格为此series图像
    //2.如果是多个窗格：
    //2.1 如果包含至少一个以渲染此series的窗格，则活跃他，或者他们的第一个
    //2.2 如果不包含，则无动作
    const { seriesId, seriesIndex } = e
    activeSeriesIndex.value = seriesIndex
    if (!seriesId) return
    const elements = Array.isArray(domCvs.value) ? domCvs.value : [domCvs.value]
    if (elements.length === 1) {
        seriesPriority.value = [seriesId]
        await renderImage()
        setFrameActive(0)
    }
}

//监听辅助定位图next
const handleAssistNext = () => {
    let crossIndex = _crossSeriesIndexs.indexOf(assistSeriesIndex.value)
    crossIndex++
    initAssistImage(crossIndex)
}

//监听辅助定位图pre
const handleAssistPre = () => {
    let crossIndex = _crossSeriesIndexs.indexOf(assistSeriesIndex.value)
    crossIndex--
    initAssistImage(crossIndex)
}

//监听information框关闭
const handleInformationClose = () => {
    showInformation.value = false
}

//监听view3d关闭
const handleView3dClose = () => {
    showView3d.value = false
}

//监听从frame导航到3d视图
const handleTo3dView = (frameIndex: number) => {
    active3dIndex.value = frameConfigs.value[frameIndex]?.seriesIndex ?? 0
    showView3d.value = true
}

//监听快捷键说明关闭
const handleHotKeyPadClose = () => {
    showHotKeyPad.value = false
}

//监听导出关闭
const handleExportSeriesClose = () => {
    exportSeriesVisible.value = false;
}

//监听标题栏菜单点击
const handleMenuBarSelected = (mark:string) => {
    if(mark=='tolist'){
        _ipcs.jumpTolist()
    }
}

//监听菜单事件
const handleMenuBack = (e: any) => {
    const { mark, value } = e
    const { viewportId } = frameConfigs.value[activeFrameIndex.value] ?? {}
    const viewport = _RenderingEngine.getViewport(viewportId)
    const { invert, rotation } = viewport.getProperties();
    switch (mark) {
        case 'f1':
            //接收本地图像
            console.log('uploader.value', uploader.value)
            uploader.value.$el.click()
            break;
        case 'f2':
            // exportSeriesVisible.value = true;
            //修改为定位文件目录
            var { p } = getUrlParams(window.location.href)
            window.$.send('GENERAL-OPEN-DIR-PATH',{pathCode:p})

            break
        case 'f3':
            //清理图像缓存
            ElMessageBox.confirm('您确认要清空图像缓存?', '提示', {
                cancelButtonText: '取消',
                confirmButtonText: '确认'
            }).then(() => {
                //清除文件缓存
                // deleteDB()
                //清除定位线缓存
                deleteStorageSamilar('ASL:')
                ElMessage({
                    message: '清理成功！',
                })
            }).catch(() => { })
            break;
        case 't1':
            //切换窗格
            layoutConfig.value = value
            localStorage.setItem(`LayoutConfig:${_studyInfo.device}`, JSON.stringify(value));
            nextTick(async () => {
                initSeriesPriority()
                await renderImage()
                activeSeriesIndex.value = 0
                setFrameActive(0)
                _RenderingEngine?.resize()
            })
            break;
        case 't2':
            //预设wwwc
            var w = value[0]
            var c = value[1]
            viewport.setProperties({ voiRange: { upper: w / 2 + c, lower: c - w / 2 } })
            viewport.render()
            break;
        case 't12':
            //全屏，已经隐藏了toolPad，需要隐藏序列选择器
            domImageSelector.value.hide()
            break;
        case 't3':
            //反色
            viewport.setProperties({ invert: !invert });
            viewport.render();
            break
        case 't4':
            //旋转90度
            viewport.setProperties({ rotation: rotation + 90 });
            viewport.render();
            break
        case 't5':
            //垂直镜像
            var { flipVertical } = viewport.getCamera();
            viewport.setCamera({ flipVertical: !flipVertical });
            viewport.render();
            break
        case 't6':
            //水平镜像
            var { flipHorizontal } = viewport.getCamera();
            viewport.setCamera({ flipHorizontal: !flipHorizontal });
            viewport.render();
            break
        case 's4':
            //重置镜头和属性
            viewport.resetCamera();
            viewport.resetProperties();
            viewport.render();
            break
        case 's5':
            //填满
            viewport.setOptions({ displayArea: { type: 'FIT' } });
            viewport.render();
            break
        case 's6':
            //实际
            viewport.setOptions({ displayArea: { type: 'SCALE' } });
            viewport.render();
            break
        case 's8':
            //播放
            if (!playStatus.value[activeFrameIndex.value]) {
                csToolsUtilities.cine.playClip(calcViewportInputArray.value[activeFrameIndex.value]?.element, { framesPerSecond: 8 });
                playStatus.value[activeFrameIndex.value] = true
            }
            break
        case 's9':
            //停止
            if (playStatus.value[activeFrameIndex.value]) {
                csToolsUtilities.cine.stopClip(calcViewportInputArray.value[activeFrameIndex.value]?.element);
                playStatus.value[activeFrameIndex.value] = false
            }
            break
        case 's10':
            //上一帧
            _RenderingEngine.getViewport(calcViewportInputArray.value[activeFrameIndex.value]?.viewportId).scroll(-1)
            break
        case 's11':
            //下一帧
            _RenderingEngine.getViewport(calcViewportInputArray.value[activeFrameIndex.value]?.viewportId).scroll(1)
            break
        case 's12':
            //全部停止
            for (const v of calcViewportInputArray.value) {
                csToolsUtilities.cine.stopClip(v?.element);
            }
            playStatus.value = {}
            break
        case 's13':
            //查看图像信息
            var { tags } = getInformationOfImage(cache.getImage(viewport.getCurrentImageId()))
            activeImageInformation.value = tags
            showInformation.value = true
            break
        case 't9':
            //查看3d
            showView3d.value = true
            break
        case 't11':
            //查看快捷键说明
            showHotKeyPad.value = true
            break
        default:
            break;
    }
}

//获取后台返图像数据
const getDcmData = (pid: string) => {
    return new Promise((resolve) => {
        window.$.listen('DCMVIEW-OPEN-FILE-CALL', async(e, d) => {
            //获取到后台文件流
            // console.log('收到数据', d)
            //seriesId即为原始seriesIndex
            const { seriesIndex, instanceIndex, data, coverImg, isComplete } = d
            if (isComplete) {
                //所有文件读取完成，初始化originData
                //1.整理series顺序
                _receivedList.sort((a: any, b: any) => Number(a.seriesIndex) -  Number(b.seriesIndex))
                //2.整理imageIds的顺序
                for (const { seriesIndex, imageObjs, coverImg } of _receivedList) {
                    const seriesId = seriesIndex.toString()
                    imageObjs.sort((a: any, b: any) => Number(a.instanceIndex) - Number(b.instanceIndex))
                    const imageIds = imageObjs.map((e: any) => e.imageId)
                    originData.value.push({ seriesId, imageIds, seriesIndex })
                    _seriesIndexOptions.push({ value: seriesIndex, label: `序列${(seriesIndex + 1)}` })
                    //得到需要加载的图像总数
                    needLoadImageCount.value += imageObjs.length
                    seriesCovers.value.push({
                        id: seriesId,
                        length: imageIds.length,
                        url: coverImg
                    })
                }
                console.log('finally',originData.value)
                resolve(null)
            }
            const blob = new Blob([data], { type: 'text/plain' });
            const file = new File([blob], 'test.dcm', { type: 'text/plain' });
            const imageId = wadouri.fileManager.add(file);

            let series = _receivedList.find(e => e.seriesIndex === seriesIndex)
            const otherSeries = _receivedList.filter(e => e.seriesIndex !== seriesIndex)
            if (!series) {
                series = {
                    imageObjs: [{ instanceIndex, imageId }],
                    seriesIndex,
                    coverImg
                }
            } else {
                series.imageObjs.push({ instanceIndex, imageId })
            }
            _receivedList = [series, ...otherSeries]
        })
        _ipcs.init(pid)
    })
}

/*========================================>( 钩子 )<========================================*/
onMounted(async () => {
    const { p } = getUrlParams(window.location.href)
    const dcmPath = decodeURIComponent(p)
    const dirNameStrs = dcmPath.split('\\')
    const dirName = dirNameStrs[dirNameStrs.length - 1];
    const nameStrs = dirName.split('-')
    const device = nameStrs[0]
    const age = nameStrs[1]
    const gender = nameStrs[2]
    const locate = nameStrs[3]
    const name = nameStrs[4]
    _studyInfo = { device, age, gender, locate, name }
    menuBarTitle.value = `本地阅片:${name}:${device.toUpperCase()}`
    // exportSeriesData.value = _studyInfo //TODO 导出功能不必有
    // const data = _studyInfo.risSeriesList
    await initCNR(device)
    await getDcmData(p)
    couldReference.value = !['DX'].includes(device)
    //后改成，根据缓存判断展示时的窗格
    const lsstr = localStorage.getItem(`LayoutConfig:${device}`)
    if (lsstr) {
        const lc = JSON.parse(lsstr)
        layoutConfig.value = lc
        // layoutConfig.value = [2,2]
        console.log('lsstr', lc)
    }
    //观察元素宽高变化
    const resizeObserver = new ResizeObserver(entries => {
        console.log('变化')
        deleteStorageSamilar('ASL:')
        for (const entry of entries) {
            const { width, height } = entry.contentRect;
            const cvsWH = width + '-' + height
            if (_cvsWH && cvsWH != _cvsWH) {
                _RenderingEngine?.resize()
                _AssistRenderingEngine?.resize()
            }
            _cvsWH = cvsWH
        }
    });
    // 开始观察元素
    resizeObserver.observe(domCvsBox.value);
    nextTick(async () => {
        initSeriesPriority()
        await renderImage()
        setFrameActive(0)
        loading.value = false
    })

    //监听全屏操作
    window.addEventListener('image-selector-visiable', () => {
        console.log('image-selector-visiable')
        showImageSelector.value = !showImageSelector.value
    })
})
</script>
<template>
	<div class="main-content series">
		<MenuBar :title="menuBarTitle" bar-color="#222" :menus="menuBarMenus" menus-on-right @select="handleMenuBarSelected" />
		<div class="loading" v-if="loading">
			<el-progress type="circle" :percentage="calcLoading" :format="(e: any) => e == 0 || e == 100 ? '加载中' : e + '％'" />
		</div>
		<div class="header">
			<tool-pad ref="domToolPad" :toolGroup="toolGroup" :moveEvent="frameMouseMoveEvent" @back="handleMenuBack" />
		</div>
		<div class="main">
			<div class="selector">
				<image-selector ref="domImageSelector" :covers="seriesCovers" v-if="showImageSelector" :activeIndex="activeSeriesIndex" @change="handleSeriesChanged" />
			</div>
			<div class="cvs-box" ref="domCvsBox">
				<div class="cvs-line" v-for="line, ldx in layoutConfig" :key="ldx">
					<div class="cvs" v-for="rdx in line" :class="{ active: activeFrameIndex == ftd(ldx, rdx, line) }" :key="rdx">
						<div class="control" v-if="frameConfigs[ftd(ldx, rdx, line)]">
							<div class="opt series-index">
								<el-select v-model="frameConfigs[ftd(ldx, rdx, line)].seriesIndex" size="small" @change="(e: number) => handleFrameSeriesIndexChanged(e, ftd(ldx, rdx, line))" style="width: 240px">
									<el-option v-for="item in _seriesIndexOptions" :key="item.value" :label="item.label" :value="item.value" />
								</el-select>
							</div>
							<div class="opt play-status" v-show="playStatus[ftd(ldx, rdx, line)]"><svg-icon icon-class="play" width="16" height="16" />自动播放中</div>
							<div class="func">
								<svg-icon icon-class="view3dtext" width="18" height="18" @click="handleTo3dView(ftd(ldx, rdx, line))" />
							</div>
						</div>
						<div v-else class="empty-image">
							<svg-icon style="color:#666" icon-class="empty-series" width="70" height="70" />
							<div class="icon-text">未填充序列</div>
						</div>
						<div class="viewer">
							<div ref="domCvs" class="ele" :data-index="ftd(ldx, rdx, line)" v-dragSeries="{ type: 'target', cb: handleSeriesDrag }"></div>
							<div class="scroller" v-if="frameConfigs[ftd(ldx, rdx, line)]">
								<div
									class="blocker"
									:style="{ top: `${(frameConfigs[ftd(ldx, rdx, line)]?.imageIndex - 1) / frameConfigs[ftd(ldx, rdx, line)]?.imageCount * 100}%`, height: `calc(100% / ${frameConfigs[ftd(ldx, rdx, line)]?.imageCount})` }"
								>
									<svg-icon icon-class="three-line" width="10" height="10" />
								</div>
							</div>
							<div v-if="domCvs?.length === 1 && originData.length > 1 && couldReference" class="assist-dom-box" ref="domAssistBox">
								<div class="assist-control">
									<template v-if="showAssistControl">
										<svg-icon icon-class="to-right" width="13" height="13" @click="handleAssistPre" />
										&emsp;序列：{{ assistSeriesIndex + 1 }}&emsp;
										<svg-icon icon-class="to-left" width="13" height="13" @click="handleAssistNext" />
									</template>
								</div>
								<div ref="domAssist" class="assist-dom"></div>
								<div class="screen"></div>
							</div>
						</div>
					</div>
				</div>
			</div>
		</div>
		<el-upload style="display: none;" :show-file-list="false" action="" multiple :before-upload="handleUploadDicom">
			<el-button ref="uploader" type="primary"></el-button>
		</el-upload>
		<Information v-if="showInformation" :data="activeImageInformation" @cancel="handleInformationClose" />
		<View3d v-if="showView3d" @close="handleView3dClose" :data="originData" :covers="seriesCovers" :activeIndex="active3dIndex" />
		<HotKeyPad v-if="showHotKeyPad" @close="handleHotKeyPadClose" />
		<ExportSeries v-if="exportSeriesVisible" :study="exportSeriesData" @close="handleExportSeriesClose" />
	</div>
</template>
<style lang="scss">
.main-container.series {
    .cvs-box .el-select.el-select--small {
        width: 100% !important;
        background-color: #ccc;
    }
}
</style>
<style lang="scss" scoped>
.main-content.series {

    -webkit-user-select: none;
    /* Safari */
    -moz-user-select: none;
    /* Firefox */
    -ms-user-select: none;
    /* IE10+/Edge */
    user-select: none;
    /* 标准语法 */

    width: 100vw;
    height: 100vh;
    background-color: #4d4d4d;
    display: flex;
    flex-direction: column;
    overflow: hidden;

    .header {
        width: 100%;
        display: table;
    }

    .main {
        flex: 1;
        display: flex;
        flex-direction: row;
        overflow: hidden;

        .selector {
            height: 100%;
            display: table;
        }

        .cvs-box {
            padding: 18px;
            flex: 1;
            display: flex;
            flex-direction: column;

            .cvs-line {
                width: 100%;
                flex: 1;
                display: flex;
                flex-direction: row;

                .cvs {
                    height: 100%;
                    flex: 1;
                    box-sizing: border-box;
                    border: solid 2px #555;
                    // background-color: #000;
                    position: relative;

                    &.active {
                        border: solid 2px #99CCFF;
                    }

                    .control {
                        width: 100%;
                        height: 30px;
                        background-color: #222;
                        box-sizing: border-box;
                        border-bottom: solid 1px #333;

                        .opt {
                            float: left;

                            &.series-index {
                                width: 75px;
                                height: 22px;
                                margin: 2px 5px;
                            }

                            &.play-status {
                                line-height: 30px;
                                color: #FFFF66;
                                margin-left: 6px;
                                font-size: 12px;
                            }
                        }

                        .func {
                            float: right;
                            margin: 3px 6px;
                            width: 18px;
                            height: 18px;
                            color: #ccc;
                            cursor: pointer;

                            &:hover {
                                color: #FFFF99;
                            }
                        }
                    }

                    .empty-image {
                        position: absolute;
                        top: 0;
                        bottom: 0;
                        left: 0;
                        right: 0;
                        width: 71px;
                        height: 71px;
                        margin: auto;

                        .icon-text {
                            color: #666;
                            text-align: center;
                            font-size: 12px;
                        }
                    }

                    .viewer {
                        width: 100%;
                        height: calc(100% - 30px);

                        .ele {
                            float: left;
                            width: calc(100% - 10px);
                            height: 100%;
                            border: none;
                            outline: none;
                        }

                        .scroller {
                            float: left;
                            width: 10px;
                            height: 100%;
                            background-color: #222;
                            position: relative;

                            .blocker {
                                width: 100%;
                                height: 50px;
                                background-color: #99CCCC;
                                position: absolute;
                                top: 0;
                                left: 0;
                                box-sizing: border-box;
                                display: flex;
                                justify-content: center;
                                align-items: center;
                            }
                        }

                        .assist-dom-box {
                            width: 20vh;
                            height: 30vh;
                            position: absolute;
                            bottom: 1px;
                            right: 11px;
                            border: solid 1px #ccc;
                            background-color: #000;

                            .assist-control {
                                width: 100%;
                                height: 30px;
                                color: #888;
                                text-align: center;
                                font-size: 13px;
                                line-height: 30px;

                                .svg-icon {
                                    cursor: pointer;

                                    &:hover {
                                        color: #99CCFF;
                                    }
                                }
                            }

                            .assist-dom {
                                width: 100%;
                                height: calc(100% - 30px);


                            }

                            .screen {
                                width: 100%;
                                height: calc(100% - 30px);
                                position: absolute;
                                bottom: 0;
                                right: 0;
                            }
                        }
                    }

                }
            }
        }
    }

    .loading {
        position: absolute;
        width: 100vw;
        height: 100vh;
        background-color: rgba(0, 0, 0, 0.9);
        z-index: 99;
        display: flex;
        justify-content: center;
        align-items: center;
    }
}
</style>
